#include "http_hls_connection.h"

#include "public_module//hls_protocol/hls_m3u8_parser.h"
#include "public_module/http_connection/http_connection.h"

#include <cstdio>
#include <memory>
#include <string>
HttpHlsConnection::HttpHlsConnection(Loop * loop)
{
    m_loop      = loop;
    m_http_conn = nullptr;
    m_state     = false;
}

void HttpHlsConnection::SetOnMessageFn(OnMessageFn && fn)
{
    m_message_fn = fn;
}

void HttpHlsConnection::SetMediaFileFn(OnMediaFileFn && fn)
{
    m_media_file_fn = fn;
}

void HttpHlsConnection::SetOnDisconnfn(OnDisConnfn && fn)
{
    m_disconn_fn = fn;
}

void HttpHlsConnection::CloseConnection() const
{
    if (m_http_conn)
    {
        m_http_conn->Close();
    }
}

int HttpHlsConnection::InitHlsUrl(const std::string & url)
{
    int  result   = 0;
    auto protocol = ProtocolParser::ParserUrl(url);
    if (protocol.m_host.empty())
    {
        result = -1;
    }
    else
    {
        m_url           = url;
        m_protocol_data = protocol;
        result          = 1;
        m_state         = false;
    }
    if (!m_http_conn && !m_protocol_data.m_host.empty())
    {
        m_http_conn = std::make_shared<HttpConnection>(m_loop);
        m_http_conn->InitCallbackFn([this](auto con, auto resp) { this->OnConnection(con, resp); },
                                    [this](auto con, auto resp) { this->OnMessage(con, resp); },
                                    [this](auto con) { this->OnDisconn(con); });
        int enable_tls = m_protocol_data.m_protocol.m_use_tls_or_dtls;
        int ret        = m_http_conn->InitHttpConnect(m_protocol_data.m_host, m_protocol_data.m_port, enable_tls);
        if (ret < 0)
        {
            result = -1;
        }
    }
    else
    {
        if (m_http_conn)
        {
            HttpRequest request;
            request.AddHeaderLine("GET", m_protocol_data.m_uri, "HTTP/1.1");
            request.AddHeaderSign("Host", m_protocol_data.m_host + ":" + std::to_string(m_protocol_data.m_port));
            request.AddHeaderSign("User-Agent", "curl/8.4.0-DEV");
            request.AddHeaderSign("Connection", "keep-alive");
            request.AddHeaderSign("Accept", "*/*");
            printf("uri : %s.\n", m_protocol_data.m_uri.c_str());
            m_http_conn->SendRequest(request);
        }
    }
    return result;
}

void HttpHlsConnection::OnConnection(HttpConnection * conn, int result) const
{
    printf("connect to %s server result : %d.\n", m_protocol_data.m_host.c_str(), result);
    if (result < 0)
    {
        return;
    }
    HttpRequest request;
    request.AddHeaderLine("GET", m_protocol_data.m_uri, "HTTP/1.1");
    request.AddHeaderSign("Host", m_protocol_data.m_host + ":" + std::to_string(m_protocol_data.m_port));
    request.AddHeaderSign("User-Agent", "curl/8.4.0-DEV");
    request.AddHeaderSign("Connection", "keep-alive");
    request.AddHeaderSign("Accept", "*/*");
    printf("uri : %s.\n", m_protocol_data.m_uri.c_str());
    m_http_conn->SendRequest(request);
}

void HttpHlsConnection::OnMessage(HttpConnection * conn, HttpResponse * response)
{
    printf("on message code %s %s.\n", response->GetCode().c_str(), response->GetNote().c_str());
    if (response->GetCode() == "200")
    {
        printf("body size : %ld.\n", response->Body().size());
        if (m_url.find(".m3u8") != std::string::npos)
        {
            int           use_length = 0;
            HlsM3u8Parser parser;
            int result = parser.Parser(response->Body().data(), static_cast<int>(response->Body().size()), use_length);
            if (result >= 0)
            {
                m_state = true;
                if (m_message_fn)
                {
                    m_message_fn(parser.HlsMessage());
                }
            }
        }
        else
        {
            m_state = true;
            if (m_media_file_fn)
            {
                m_media_file_fn(m_url, response->Body().data(), static_cast<int>(response->Body().size()));
            }
        }
    }
}

void HttpHlsConnection::OnDisconn(HttpConnection * conn)
{
    printf("disconnection %s:%d.\n", m_protocol_data.m_host.c_str(), m_protocol_data.m_port);
    // reconnecting to server
    m_http_conn->Close();
    m_http_conn = nullptr;
    if (!m_state)
    {
        InitHlsUrl(m_url);
    }
}
